package com.auroramanito.uaa.util;
import com.auroramanito.uaa.config.AppProperties;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

@RequiredArgsConstructor
@Component
public class JwtUtil {

    //用于签名的访问令牌的密钥
    public static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
    //用于签名的刷新令牌的密钥
    public static final Key refreshKey = Keys.secretKeyFor(SignatureAlgorithm.HS512);

    private final AppProperties appProperties;

    //创建访问令牌
    public String createAccessToken(UserDetails userDetails){
        return createJwtToken(userDetails,key,appProperties.getJwt().getAccessTokenExpireTime());
    }

    //创建刷新令牌
    public String createRefreshToken(UserDetails userDetails){
        return createJwtToken(userDetails,refreshKey,appProperties.getJwt().getRefreshTokenExpireTime());
    }


    //创建刷新令牌
    public String createAccessTokenWithRefreshToken(String token){
        return parseClaims(token,refreshKey)
                .map(claims -> Jwts.builder()
                        .setClaims(claims)
                        .setExpiration(new Date(System.currentTimeMillis() + appProperties.getJwt().getAccessTokenExpireTime()))
                        .setIssuedAt(new Date())
                        .signWith(key,SignatureAlgorithm.HS512)
                        .compact()
                ).orElseThrow(() -> new AccessDeniedException("访问被拒绝"));

    }

    public Optional<Claims> parseClaims(String token,Key key){

        try {
            val claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
            return Optional.of(claims);
        } catch (Exception e) {
            return Optional.empty();
        }
    }
    //创建访问令牌
    public boolean validateAccessTokenWithoutExpiration(String token){
        return validateToken(token,key,false);
    }

    //创建访问令牌
    public boolean validateAccessToken(String token){
        return validateToken(token,key,true);
    }

    //创建刷新令牌
    public boolean validateRefreshToken(String token){
        return validateToken(token,refreshKey,true);
    }

    /**
     * 判断token是否可用
     * */
    public boolean validateToken(String token,Key key,boolean isExcpiredInvalid){
        try {
            Jwt parse = Jwts.parserBuilder().setSigningKey(key).build().parse(token);
            return true;
        } catch (ExpiredJwtException e) {
            //已经过期是违法的，当出现过期时返回false
            return !isExcpiredInvalid;
        } catch (MalformedJwtException e) {
            return false;
        } catch (SignatureException e) {
            return false;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }

    /**
     * JWTToken 生成策略
     * 1、传入用户authorities。
     * 2、主题放入的是用户名
     * 3、签发时间
     * 4、过期时间
     * 5、签名
     * */
    public String createJwtToken(UserDetails userDetails,Key key,long timeToExpire){
        val now = System.currentTimeMillis();
        String compact = Jwts.builder()
                .setId("mooc")
                .claim("authorities", userDetails.getAuthorities().stream()
                        .map(GrantedAuthority::getAuthority).collect(toList()))
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date(now))
                .setExpiration(new Date(now + timeToExpire))
                .signWith(key, SignatureAlgorithm.HS512)
                .compact();
        return compact;

    }



}
